/*
 * ChessTable.cpp
 *
 *  Created on: 18 Jan 2011
 *      Author: sinan
 */

#include "ChessTable.h"

ChessMan ChessTable::ChessTableMatrix[8][8];
ChessMan ChessTable::UndoMatrix[8][8];
vector<ChessMan> ChessTable::ChessMenDeadBlack;
vector<ChessMan> ChessTable::ChessMenDeadWhite;
vector<VisitableCoordinate> ChessTable::MovementList;
vector<ChessTableCoordinate> ChessTable::EnemyChessMenCoordinateList;
ChessTableCoordinate ChessTable::selectedCoordinate;
vector<VisitableCoordinate> ChessTable::selectedCoordinateMovementList;
ChessMan ChessTable::LastEatenBlackChessMan;
ChessMan ChessTable::LastEatenWhiteChessMan;

ChessTable::ChessTable() {

}

ChessTable::~ChessTable() {
	// TODO Auto-generated destructor stub
}

void ChessTable::EqualTwoArrays(ChessMan arrayOriginal[8][8],
		ChessMan arrayToEqual[8][8]) {
	int i, j;

	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++) {
			arrayToEqual[i][j] = arrayOriginal[i][j];
		}
	}
}

ChessTableMtrx ChessTable::MakeMovement(ChessTableCoordinate oldCoord,
		ChessTableCoordinate newCoord, ChessMan matrix[8][8],
		bool IsMovementReal) {
	int i = 0;
	SoundSource ss;
	ChessTableMtrx ctMtrx;
	ChessMan c = ChessMan();
	ctMtrx.isChanged = false;

	for (i = 0; i < ChessTable::MovementList.size(); i++) {
		if (ChessTable::MovementList.at(i).ctCoord.x == newCoord.x
				&& ChessTable::MovementList.at(i).ctCoord.y == newCoord.y) {
			ctMtrx.isChanged = true;
			if (matrix[newCoord.x][newCoord.y].color != ChessManColor_NULL) {
				if (matrix[newCoord.x][newCoord.y].color == ChessManColor_Black) {
					// bir if daha koyarak gercek hamleyse pushback yapılmalı
					if (IsMovementReal) {
						ChessTable::ChessMenDeadBlack.push_back(
								matrix[newCoord.x][newCoord.y]);
						ss.PlayWhistle();
						// son yenen tas burda belirlenir
						// sonrasında seslendirme de yapılmalı
						// tas yeme sesi ya da check mate yada check
						ChessTable::LastEatenBlackChessMan
								= matrix[newCoord.x][newCoord.y];
					}
					matrix[newCoord.x][newCoord.y]
							= matrix[oldCoord.x][oldCoord.y];
					matrix[oldCoord.x][oldCoord.y] = c;
				} else if (matrix[newCoord.x][newCoord.y].color
						== ChessManColor_White) {
					if (IsMovementReal) {
						ChessTable::ChessMenDeadWhite.push_back(
								matrix[newCoord.x][newCoord.y]);
						ss.PlayWhistle();
						// son yenen tas burda belirlenir
						ChessTable::LastEatenWhiteChessMan
								= matrix[newCoord.x][newCoord.y];
					}
					matrix[newCoord.x][newCoord.y]
							= matrix[oldCoord.x][oldCoord.y];
					matrix[oldCoord.x][oldCoord.y] = c;
				}
			} else {
				matrix[newCoord.x][newCoord.y] = matrix[oldCoord.x][oldCoord.y];
				matrix[oldCoord.x][oldCoord.y] = c;
				if (IsMovementReal) {
					ss.PlayTicTock();
				}
			}
			CheckPawnForEndLine(matrix); // piyonun vezir olması durumu
			// movement listi bosalt
			// silme islemi
			ChessTable::MovementList.erase(ChessTable::MovementList.begin(),
					ChessTable::MovementList.end());
			break;
		}

	}
	EqualTwoArrays(matrix, ctMtrx.data);
	//ctMtrx.data = matrix;
	return ctMtrx;
}

void ChessTable::CheckForBeatenChessMan() {
	if (ChessTable::LastEatenBlackChessMan.type == ChessManType_NULL
			&& ChessTable::LastEatenWhiteChessMan.type == ChessManType_NULL) {
		return;
	}

	int i = 0;
	vector<ChessMan> tempVector;
	bool flag = true;

	if (LastEatenBlackChessMan.type != ChessManType_NULL) {
		for (i = 0; i < ChessTable::ChessMenDeadBlack.size(); i++) {
			if (LastEatenBlackChessMan.type
					== ChessTable::ChessMenDeadBlack.at(i).type && flag) {
				flag = false;
			} else {
				//flag = true;
				tempVector.push_back(ChessTable::ChessMenDeadBlack.at(i));
			}
		}
		ChessTable::ChessMenDeadBlack = tempVector; //esitleme yapılır/
		tempVector.erase(tempVector.begin(), tempVector.end());
		flag = true;
	}

	if (LastEatenWhiteChessMan.type != ChessManType_NULL) {
		for (i = 0; i < ChessTable::ChessMenDeadWhite.size(); i++) {
			if (LastEatenWhiteChessMan.type
					== ChessTable::ChessMenDeadWhite.at(i).type && flag) {
				flag = false;
			} else {
				tempVector.push_back(ChessTable::ChessMenDeadWhite.at(i));
			}
		}
		ChessTable::ChessMenDeadWhite = tempVector; //esitleme yapılır/
		tempVector.erase(tempVector.begin(), tempVector.end());
		flag = true;
	}

}

bool ChessTable::IsCheckMateOrCheck(ChessMan matrix[8][8]) {

	SoundSource ss;
	int i = 0, j = 0;
	vector<Movement> ChessMen = FindAllMovements(matrix, ChessManColor_Black);
	ChessTableCoordinate kingCoord = GetKingChessManCoordinate(
			ChessManColor_White, matrix);
	if (ChessMen.empty()) {
		// WIN
		ss.PlayCheckMateWin();
		alureSleep(3.0);
		exit(0);
	} else {
		for (i = 0; i < ChessMen.size(); i++) {
			for (j = 0; j < ChessMen.at(i).toCoord.size(); j++) {
				if (kingCoord.x == ChessMen.at(i).toCoord.at(j).x &&
						kingCoord.y == ChessMen.at(i).toCoord.at(j).y) {
					ss.PlayCheck();
					break;
				}
			}

		}
	}

	ChessMen = FindAllMovements(matrix, ChessManColor_White);
	kingCoord = GetKingChessManCoordinate(ChessManColor_Black, matrix);
	if (ChessMen.empty()) {
		// LOSE
		ss.PlayCheckMateLose();
		alureSleep(3.0);
		exit(0);
	} else {
		for (i = 0; i < ChessMen.size(); i++) {
			for (j = 0; j < ChessMen.at(i).toCoord.size(); j++) {
				if (kingCoord.x == ChessMen.at(i).toCoord.at(j).x &&
						kingCoord.y == ChessMen.at(i).toCoord.at(j).y) {
					ss.PlayCheck();
					break;
				}
			}

		}
	}

}

vector<Movement> ChessTable::FindAllMovements(ChessMan chessTableMatrix[8][8],
		ChessManColor cmColor) {

	unsigned int i, j;
	Movement movement;
	vector<Movement> MovementList;
	vector<ChessTableCoordinate> SelfChessManList = GetAllSelfChessMan(
			chessTableMatrix, cmColor);

	for (i = 0; i < SelfChessManList.size(); i++) {
		GetMovementList(SelfChessManList.at(i), chessTableMatrix);
		RefineMovementList(SelfChessManList.at(i), chessTableMatrix); // sorunlu olan bu gibi
		if (!ChessTable::MovementList.empty()) {

			movement.fromCoord.x = SelfChessManList.at(i).x;
			movement.fromCoord.y = SelfChessManList.at(i).y;
			for (j = 0; j < ChessTable::MovementList.size(); j++) {
				movement.toCoord.push_back(
						ChessTable::MovementList.at(j).ctCoord);
			}
			MovementList.push_back(movement);
			movement.toCoord.erase(movement.toCoord.begin(),
					movement.toCoord.end());
			ChessTable::MovementList.erase(ChessTable::MovementList.begin(),
					ChessTable::MovementList.end());
		}

		// movement List temizlenir ve bir sonraki işleme hazır hale gelir.
	}

	return MovementList;
}

void ChessTable::RefineMovementList(ChessTableCoordinate cmCoord,
		ChessMan matrix[8][8]) {

	int i = 0, j = 0;
	int staticSize = 0;
	vector<VisitableCoordinate> tempMovementList;
	vector<VisitableCoordinate> CorrectMovementList;
	ChessMan tempChessTableMatrix[8][8];
	ChessMan nullCM = ChessMan();

	if (ChessTable::MovementList.size() == 0) {
		return; // bu kontrol yapılmalı
	}

	tempMovementList = ChessTable::MovementList;

	//tempChessTableMatrix = ChessTable::ChessTableMatrix;
	EqualTwoArrays(matrix, tempChessTableMatrix);
	staticSize = tempMovementList.size();

	//	for (j = staticSize - 1; j > -1; j--) {
	for (j = 0; j < staticSize; j++) {

		matrix[tempMovementList.at(j).ctCoord.x][tempMovementList.at(j).ctCoord.y]
				= matrix[cmCoord.x][cmCoord.y];
		// gidilebilecek yere konur.

		matrix[cmCoord.x][cmCoord.y] = nullCM;
		// sonrasında kendi yeri de boşaltılır.

		GetAllEnemyChessMen(
				matrix[tempMovementList.at(j).ctCoord.x][tempMovementList.at(j).ctCoord.y].color,
				matrix);
		// su an enemyChessmanlist karsı taraftaki taslar yer alıyor.
		// taşlardan birinin üstüne gitmisse ona göre gelir diger taslar

		// önce movementList tamamen silinir
		ChessTable::MovementList.erase(ChessTable::MovementList.begin(),
				ChessTable::MovementList.end());

		// sonra hamle yapılmıs halde diğer taşların gidebileceği
		// tüm alanlar bulunur.
		for (i = 0; i < ChessTable::EnemyChessMenCoordinateList.size(); i++) {
			GetMovementList(ChessTable::EnemyChessMenCoordinateList.at(i),
					matrix);
		}

		if (IsKingInDanger(
				matrix[tempMovementList.at(j).ctCoord.x][tempMovementList.at(j).ctCoord.y].color,
				matrix)) {
			//tempMovementList.erase(tempMovementList.begin() + j);
			// onaylanmayan koordinat silinir.
		} else {
			CorrectMovementList.push_back(tempMovementList.at(j));
		}

		EqualTwoArrays(tempChessTableMatrix, matrix);
		// tekrar ilk satranc tahtasına dönülür.


	}

	//EqualTwoArrays(tempChessTableMatrix, ChessTable::ChessTableMatrix);
	//ChessTable::ChessTableMatrix = tempChessTableMatrix;
	// tekrar ilk satranc tahtasına dönülür.


	ChessTable::MovementList = CorrectMovementList;
	// son olarak arıtılmıs movementList verilir.

	ChessTable::EnemyChessMenCoordinateList.erase(
			EnemyChessMenCoordinateList.begin(),
			EnemyChessMenCoordinateList.end());
	//once enemylist icindekiler silinir.

}
vector<ChessTableCoordinate> ChessTable::GetAllSelfChessMan(
		ChessMan chessTableMatrix[8][8], ChessManColor cmColor) {

	int i, j;
	ChessTableCoordinate ctCoord;
	vector<ChessTableCoordinate> SelfChessManList;

	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++) {
			if (chessTableMatrix[i][j].color == cmColor) {
				ctCoord.x = i;
				ctCoord.y = j;
				SelfChessManList.push_back(ctCoord);
				//sahip olunan tasların koordinatları eklenir.
			}
		}
	}
	return SelfChessManList;
}
bool ChessTable::IsKingInDanger(ChessManColor cmColor, ChessMan matrix[8][8]) {
	int i = 0;

	ChessTableCoordinate ctCoord = GetKingChessManCoordinate(cmColor, matrix);

	for (i = 0; i < ChessTable::MovementList.size(); i++) {
		if (ChessTable::MovementList.at(i).ctCoord.x == ctCoord.x
				&& ChessTable::MovementList.at(i).ctCoord.y == ctCoord.y) {
			return true;
		}
	}
	return false;
}

ChessTableCoordinate ChessTable::GetKingChessManCoordinate(
		ChessManColor cmColor, ChessMan matrix[][8]) {
	int i, j;
	ChessTableCoordinate ctCoord;
	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++) {
			if (matrix[i][j].color == cmColor && matrix[i][j].type
					== ChessManType_King) {
				ctCoord.x = i;
				ctCoord.y = j;
				break;
				return ctCoord;
			}
		}
	}
}

void ChessTable::GetAllEnemyChessMen(ChessManColor cmColor,
		ChessMan matrix[8][8]) {

	int i, j;
	ChessTableCoordinate ctCoord;

	ChessTable::EnemyChessMenCoordinateList.erase(
			EnemyChessMenCoordinateList.begin(),
			EnemyChessMenCoordinateList.end());
	//once enemylist icindekiler silinir.

	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++) {
			if (matrix[i][j].color != cmColor && matrix[i][j].color
					!= ChessManColor_NULL) {
				ctCoord.x = i;
				ctCoord.y = j;
				EnemyChessMenCoordinateList.push_back(ctCoord);
				//karsı tarafın sahip oldugu tasların koordinatları eklenir.
			}
		}
	}
}

void ChessTable::GetMovementList(ChessTableCoordinate cmCoord,
		ChessMan matrix[8][8]) {

	if (cmCoord.x == -100 && cmCoord.y == -100) {
		return;
	}

	Bishop b = Bishop();
	Rook r = Rook();
	Knight knght = Knight();
	Queen qn = Queen();
	Pawn pwn = Pawn();
	King kng = King();

	if (Game::chessPlayerTurn == ChessPlayerTurn_White
			&& matrix[cmCoord.x][cmCoord.y].color == ChessManColor_White) {
		Game::ChosenChessManCoordinate = cmCoord;
		//kendisinin karesinin cizilecegi alan
	}

	if ((matrix[cmCoord.x][cmCoord.y].color == ChessManColor_White
			&& Game::chessPlayerTurn == ChessPlayerTurn_White)
			|| Game::chessPlayerTurn == ChessPlayerTurn_Black
			|| matrix[cmCoord.x][cmCoord.y].color == ChessManColor_Black
			|| ChessTable::EnemyChessMenCoordinateList.size() > 0) {
		// refine icin konmus son enemyChessMen
		switch (matrix[cmCoord.x][cmCoord.y].type) {
		case ChessManType_Bishop:
			b.GetMovementList(cmCoord, matrix);
			break;
		case ChessManType_Rook:
			r.GetMovementList(cmCoord, matrix);
			break;
		case ChessManType_Knight:
			knght.GetMovementList(cmCoord, matrix);
			break;
		case ChessManType_Queen:
			qn.GetMovementList(cmCoord, matrix);
			break;
		case ChessManType_Pawn:
			pwn.GetMovementList(cmCoord, matrix);
			break;
		case ChessManType_King:
			kng.GetMovementList(cmCoord, matrix);
			break;
		default:
			break;
		} // end of switch


	} else if ((matrix[cmCoord.x][cmCoord.y].color == ChessManColor_Black
			&& Game::chessPlayerTurn == ChessPlayerTurn_White)
			|| (matrix[cmCoord.x][cmCoord.y].color == ChessManColor_White
					&& Game::chessPlayerTurn == ChessPlayerTurn_Black)) {

		// not your turn yazdırılsın.
		//ScreenOperations::WriteToScreen(-1.5, 1.0, "Yanlis Tas Secimi!");

		Game::gameMessage.message = "Yanlis Tas Secimi !";

	}

}

void ChessTable::InitializeChessTableMatrixWithNullChessMen() {

	int i, j;
	ChessMan c = ChessMan();
	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++) {
			ChessTable::ChessTableMatrix[i][j] = c;
		}
	}
}

void ChessTable::FillChessTableMatrixForBeginning() {

	int i = 0;

	Rook wrk = Rook(ChessManColor_White);
	Knight wknght = Knight(ChessManColor_White);
	Bishop wbshp = Bishop(ChessManColor_White);
	Queen wqn = Queen(ChessManColor_White);
	King wkng = King(ChessManColor_White);
	Pawn wpwn = Pawn(ChessManColor_White);

	ChessTable::ChessTableMatrix[0][0] = wrk;
	ChessTable::ChessTableMatrix[7][0] = wrk;

	ChessTable::ChessTableMatrix[1][0] = wknght;
	ChessTable::ChessTableMatrix[6][0] = wknght;

	ChessTable::ChessTableMatrix[2][0] = wbshp;
	ChessTable::ChessTableMatrix[5][0] = wbshp;

	ChessTable::ChessTableMatrix[3][0] = wqn;
	ChessTable::ChessTableMatrix[4][0] = wkng;

	for (i = 0; i < 8; i++) {
		ChessTable::ChessTableMatrix[i][1] = wpwn;
	}

/*
//	 ChessTable::ChessTableMatrix[0][3] = wqn;
	 ChessTable::ChessTableMatrix[3][5] = wbshp;
	 ChessTable::ChessTableMatrix[2][4] = wrk;
	 ////ChessTable::ChessTableMatrix[0][5] = wqn;
//	 ChessTable::ChessTableMatrix[1][5] = wbshp;

//	 ChessTable::ChessTableMatrix[2][5] = wpwn;  // sıkıntı yaratan bu

//	 ChessTable::ChessTableMatrix[6][5] = wbshp;
	 ChessTable::ChessTableMatrix[7][5] = wpwn;
	 ChessTable::ChessTableMatrix[5][4] = wknght;
	 ChessTable::ChessTableMatrix[3][4] = wknght;
*/

	/// White Completed

	Rook brk = Rook(ChessManColor_Black);
	Knight bknght = Knight(ChessManColor_Black);
	Bishop bbshp = Bishop(ChessManColor_Black);
	Queen bqn = Queen(ChessManColor_Black);
	King bkng = King(ChessManColor_Black);
	Pawn bpwn = Pawn(ChessManColor_Black);

	ChessTable::ChessTableMatrix[0][7] = brk;
	ChessTable::ChessTableMatrix[7][7] = brk;

	ChessTable::ChessTableMatrix[1][7] = bknght;
	ChessTable::ChessTableMatrix[6][7] = bknght;

	ChessTable::ChessTableMatrix[2][7] = bbshp;
	ChessTable::ChessTableMatrix[5][7] = bbshp;

	ChessTable::ChessTableMatrix[3][7] = bqn;
	ChessTable::ChessTableMatrix[4][7] = bkng;

	//ChessTable::ChessTableMatrix[0][4] = bqn; // deneme amaclı

	for (i = 0; i < 8; i++) {
		ChessTable::ChessTableMatrix[i][6] = bpwn;
	}


	// Black completed.
	// ilk hamlesi olan piyonlar listeye atılmalı
}

ChessManColor ChessTable::GetReverseColor(ChessManColor cmColor) {

	if (cmColor == ChessManColor_Black) {
		return ChessManColor_White;
	} else {
		return ChessManColor_Black;
	}

}

void ChessTable::CheckPawnForEndLine(ChessMan matrix[8][8]) {

	int i = 0;

	for (i = 0; i < 8; i++) {
		if (matrix[i][0].type == ChessManType_Pawn && matrix[i][0].color
				== ChessManColor_Black) {
			// siyah piyon vezire cevrilir
			matrix[i][0].type = ChessManType_Queen;
		} else if (matrix[i][7].type == ChessManType_Pawn && matrix[i][7].color
				== ChessManColor_White) {
			// beyaz piyon vezire cevrilir
			matrix[i][7].type = ChessManType_Queen;
		}
	}

}

